package plgbase

import (
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"time"
)

/*
**

	input
*/
type InnerPlug struct {
	ownerPlug   interface{}
	TypeStr     string
	plug        interface{}
	plugID      string
	ReleaseFlag int
}

func NewInnerPlug() *InnerPlug {
	return &InnerPlug{}
}

func NewInnerPlug2(owner interface{}) *InnerPlug {
	rval := &InnerPlug{}
	rval.ConfigOwnerPlug(owner)
	return rval
}

func (this *InnerPlug) ConfigOwnerPlug(plg interface{}) {
	this.ownerPlug = plg
}

func (this *InnerPlug) Release() {
	this.ReleaseFlag = 1
	this.plug = nil
}

func (this *InnerPlug) IsValid() bool {
	return this.ReleaseFlag == 0 && this.CheckGetPlug() != nil
}

func (this *InnerPlug) String() string {
	if this.plug == nil {
		return fmt.Sprintf("[%s]NULL", this.plugID)
	} else {
		return fmt.Sprintf("[%s]%v", this.plugID, this.plug)
	}
}

func (this *InnerPlug) StatusString() string {
	if this.plug == nil {
		return fmt.Sprintf("[%s]NULL", this.plugID)
	} else {
		return fmt.Sprintf("[%s]%v", this.plugID, this.plug)
	}
}

/*
*

	{
	    "id":"ex"
	}
*/
func (this *InnerPlug) ReloadConf(conf *wrapper.SuperValue) (ischanged bool) {
	if conf == nil {
		this.ConfigInnerPlugId("")
		return
	}

	if conf.IsObject() {
		conf.CheckStrFunc("id", func(strv string) {
			this.ConfigInnerPlugId(strv)
		})
	} else {
		this.ConfigInnerPlugId(conf.String())
	}
	return
}

func (this *InnerPlug) ConfigInnerPlug(plg interface{}) {
	this.plug = plg
}

func (this *InnerPlug) ConfigInnerPlugId(plgid string) {
	if this.plugID != plgid {
		this.plugID = plgid
		this.TypeStr = this.plugID
		if len(this.plugID) == 0 {
			this.plug = nil
		} else {
			ex := FindPluginByID(this.plugID)
			this.plug = ex
		}
	}
}

// 对象评级
func (this *InnerPlug) GradeOne(val interface{}, grade int, args ...interface{}) bool {
	plg := this.CheckGetPlug()
	if plg == nil {
		return false
	}

	if intf, ok := plg.(IPickOne); ok {
		intf.GradeOne(val, grade, args...)
		return true
	}
	return false
}

/*
*

	释放对象
*/
func (this *InnerPlug) ReleaseOne(val interface{}, args ...interface{}) bool {
	plg := this.CheckGetPlug()
	if plg == nil {
		return false
	}

	if intf, ok := plg.(IPickOne); ok {
		intf.ReleaseOne(val, args...)
		return true
	}
	return false
}

func (this *InnerPlug) PickOne(args ...interface{}) interface{} {
	plg := this.CheckGetPlug()
	if plg == nil {
		return nil
	}

	if intf, ok := plg.(IPickOne); ok {
		return intf.PickOne(args...)
	} else {
		return plg // 使用内置插件
	}
}

func (this *InnerPlug) GetPlg() interface{} {
	return this.plug
}

func (this *InnerPlug) GetInnerPlugID() string {
	return this.plugID
}

func (this *InnerPlug) CheckGetPlug() interface{} {
	ex := this.plug
	if ex == nil && len(this.plugID) > 0 {
		ex = FindPluginByID(this.plugID)
		if ex != nil {
			this.plug = ex
		}
	} else if PlugIsReleased(ex) == 1 { // 已经释放 重新获取
		this.plug = nil
		ex = FindPluginByID(this.plugID)
		if ex != nil {
			this.plug = ex
		}
	}
	return ex
}

func (this *InnerPlug) DispatchData(channelid string, sender interface{}, data interface{}, tag interface{}) (err error) {
	if this.ReleaseFlag == 1 {
		return fmt.Errorf("已经被释放")
	}
	ex := this.CheckGetPlug()
	if ex == nil {
		return fmt.Errorf("找不到内置插件[%s]", this.plugID)
	}

	return TryDispatchData(ex, channelid, sender, data, tag)

	//if sc, ok := ex.(IDispatchData); ok {
	//	return sc.DispatchData(channelid, sender, data, tag)
	//	//if err != nil {
	//	//	golog.Warnf("[%s]分发数据出现异常:%s", this.TypeStr, err.Error())
	//	//}
	//} else if sc, ok := ex.(ISendKVs); ok {
	//	return sc.SendKVs(channelid, data)
	//	//if err != nil {
	//	//	golog.Warnf("[%s]分发数据出现异常:%s", this.TypeStr, err.Error())
	//	//}
	//} else {
	//	return fmt.Errorf("内置插件[%s]不支持分发接口", this.plugID)
	//	//golog.Warnf( "发送插件不支持ISendKVs")
	//}
}

//func (this *InnerPlug) DispatchData(topic string, sender interface{}, data interface{}, tag interface{}) {
//	if this.ReleaseFlag == 1 {
//		return
//	}
//	ex := this.CheckGetPlug()
//	if ex == nil {
//		return
//	}
//
//	if sc, ok := ex.(IDispatchData); ok {
//		err := sc.DispatchData(topic, sender, data, tag)
//		if err != nil {
//			golog.Warnf("[%s]分发数据出现异常:%s", this.TypeStr, err.Error())
//		}
//	} else if sc, ok := ex.(ISendKVs); ok {
//		err := sc.SendKVs(topic, data)
//		if err != nil {
//			golog.Warnf("[%s]分发数据出现异常:%s", this.TypeStr, err.Error())
//		}
//	} else {
//		golog.Warnf( "发送插件不支持ISendKVs")
//	}
//}

func (this *InnerPlug) UnSubscribeEx(topic string, id interface{}) {
	ex := this.CheckGetPlug()
	if ex == nil {
		return
	}
	if sc, ok := ex.(utils.IUnSubscribe); ok {
		sc.UnsubscribeChannel(topic, id)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().UnsubscribeChannel(topic, id)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.UnsubscribeChannel(topic, id)
	} else {
		return
	}
}

/*
**

	可以重复执行, 不会取消之前的订阅, 需要自己执行取消
*/
func (this *InnerPlug) SubscribeEx(topic string, id interface{}, onInput utils.SubscribeCallback) (subtopic string, err error) {
	if this.ReleaseFlag == 1 {
		return "", fmt.Errorf("当前插件已经被释放")
	}

	if len(topic) == 0 {
		return "", fmt.Errorf("请指定订阅主题!")
	}

	ex := this.CheckGetPlug()
	if ex == nil {
		return "", fmt.Errorf("[%s]找不到对应的插件进行订阅", this.plugID)
	}

	if sc, ok := ex.(utils.ISubscribeEx); ok {
		return sc.SubscribeChannelEx(topic, id, onInput)
	} else if sc, ok := ex.(utils.ISubscribe); ok {
		sc.SubscribeChannel(topic, id, onInput)
	} else if sc, ok := ex.(IGetSubscriber); ok {
		sc.GetSubscriber().SubscribeChannel(topic, id, onInput)
	} else if sc, ok := ex.(utils.SubscribeCenter); ok {
		sc.SubscribeChannel(topic, id, onInput)
	} else {
		return "", fmt.Errorf("[%s]插件[%v]不能进行阅", this.plugID, this.plug)
	}
	return topic, nil
}

func (this *InnerPlug) CreateMutex(id string, duration time.Duration) (rval interface{}, err error) {
	if this.ReleaseFlag == 1 {
		return nil, fmt.Errorf("当前插件已经被释放")
	}

	if lvIntf, ok := this.CheckGetPlug().(utils.IMutexOpera); ok {
		return lvIntf.CreateMutex(id, duration)
	} else {
		return nil, fmt.Errorf("[%s]插件[%v]不支持IMutexOpera", this.plugID, this.plug)
	}
}

func (this *InnerPlug) MutextLock(mutex interface{}) (err error) {
	if this.ReleaseFlag == 1 {
		return fmt.Errorf("当前插件已经被释放")
	}

	if lvIntf, ok := this.CheckGetPlug().(utils.IMutexOpera); ok {
		return lvIntf.MutextLock(mutex)
	} else {
		return fmt.Errorf("[%s]插件[%v]不支持IMutexOpera", this.plugID, this.plug)
	}
}

func (this *InnerPlug) MutextUnLock(mutex interface{}) (bool, error) {
	if this.ReleaseFlag == 1 {
		return false, fmt.Errorf("当前插件已经被释放")
	}

	if lvIntf, ok := this.CheckGetPlug().(utils.IMutexOpera); ok {
		return lvIntf.MutextUnLock(mutex)
	} else {
		return false, fmt.Errorf("[%s]插件[%v]不支持IMutexOpera", this.plugID, this.plug)
	}
}

func (this *InnerPlug) DoRequest(args ...interface{}) interface{} {
	plg := this.CheckGetPlug()
	if plg == nil {
		return fmt.Errorf("内置插件不存在")
	}
	if intf, ok := plg.(utils.IRequestIntf); ok {
		return intf.DoRequest(args...)
	} else {
		return fmt.Errorf("内置插件不支持IRequestIntf接口")
	}
}

func (this *InnerPlug) LoadOrStore(id interface{}, store interface{}) (actual interface{}, loaded bool) {
	plg := this.CheckGetPlug()
	if plg == nil {
		return nil, false
	}

	if smap, ok := plg.(ISyncMap); ok {
		return smap.LoadOrStore(id, store)
	}
	return nil, false
}

func (this *InnerPlug) LoadOrStoreDefault(id interface{}, store interface{}, def interface{}) (actual interface{}) {
	plg := this.CheckGetPlug()
	if plg == nil {
		return def
	}

	if smap, ok := plg.(ISyncMap); ok {
		actual, _ := smap.LoadOrStore(id, store)
		return actual
	}
	return def
}

func (this *InnerPlug) RemoveAndGet(id interface{}) (val interface{}, ok bool) {
	plg := this.CheckGetPlug()
	if plg == nil {
		return nil, false
	}

	if smap, ok := plg.(ISyncMap); ok {
		return smap.RemoveAndGet(id)
	}
	return nil, false
}

func (this *InnerPlug) SetMapValue(key string, value interface{}) error {
	if this.ReleaseFlag == 1 {
		return fmt.Errorf("插件已经释放!")
	}

	plg := this.CheckGetPlug()
	if plg == nil {
		return fmt.Errorf("插件不存在")
	}

	intf, ok := plg.(IPlgMap)
	if !ok {
		return fmt.Errorf("插件[%s]不支持IPlgMap接口", this.plugID)
	}
	return intf.SetValue(key, value)
}

func (this *InnerPlug) GetMapValue(key string) (val interface{}, err error) {
	if this.ReleaseFlag == 1 {
		return nil, fmt.Errorf("插件已经释放!")
	}

	plg := this.CheckGetPlug()
	if plg == nil {
		return nil, fmt.Errorf("插件不存在")
	}

	intf, ok := plg.(IPlgMap)
	if !ok {
		return nil, fmt.Errorf("插件[%s]不支持IPlgMap接口", this.plugID)
	}
	return intf.GetValue(key)
}

func (this *InnerPlug) RemoveMapValue(key string) (ok bool, err error) {
	if this.ReleaseFlag == 1 {
		return false, fmt.Errorf("插件已经释放!")
	}

	plg := this.CheckGetPlug()
	if plg == nil {
		return false, fmt.Errorf("插件不存在")
	}

	intf, ok := plg.(IPlgMap)
	if !ok {
		return false, fmt.Errorf("插件[%s]不支持IPlgMap接口", this.plugID)
	}
	return intf.RemoveValue(key)
}
